from time import timezone

from django.db import transaction
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema

from lab.common.auth import LoginRequired
from lab.common.base_model_view_set import BaseModelViewSet
from lab.common.enums import ErrorCodeEnum, CreditScoreEnum
from lab.common.id_factory import id_factory
from lab.common.pagination import CustomPageNumberPagination
from lab.common.response import OK, BadRequest
from lab.credit.models import CreditScoreDetail
from lab.credit.serializers import CreditScoreListSerializer, CreditScoreDetailSerializer
from lab.user.models import ExtendedUser

CREDIT_STATUS_DICT = {
    'pending': 0,
    'pass': 1,
    'reject': 2,
    'cancel': 3
}

CREDIT_SCORE_LIST = [CreditScoreEnum.EXPERIMENTAL_RESULTS, CreditScoreEnum.COMPETITION_REWARDS,
                     CreditScoreEnum.PROCESS_ASSISTANTS, CreditScoreEnum.TEACH_ASSISTANT,
                     CreditScoreEnum.BREAK_APPOINTMENT,
                     CreditScoreEnum.NOT_CLEAN, CreditScoreEnum.OVERTIME, CreditScoreEnum.TRANSFER_SCORE]


class CreditScoreViewSet(BaseModelViewSet):
    """
    list:
        获取当前用户信用分相关信息list
        
    create:
        创建信用分申请

    retrieve:
        获取信用分申请详情

    transfer_credit:
        转让信用分
    """
    authentication_class = (LoginRequired,)
    pagination_class = CustomPageNumberPagination

    def list(self, request, *args, **kwargs):
        user_id = request.user.id if request.user.id else 1
        credit_list = CreditScoreDetail.objects.filter(user_id=user_id).order_by('-created_time').all()
        return self.get_paginated_response(
            self.paginate_queryset(CreditScoreListSerializer(credit_list, many=True).data))

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='用户Id'),
                'apply_type': openapi.Schema(type=openapi.TYPE_STRING,
                                             description='申请类型,9为字符串， 01代表申请/扣分类型, 000000000: 分别代表:实验成果, '
                                                         '竞赛奖励, 协助加工, 助教助研, 爽约, 未打扫, 耗材用量过多, 超时, 信用分转让'),
                'reason': openapi.Schema(type=openapi.TYPE_STRING, description='申请理由'),
                'picture_url': openapi.Schema(type=openapi.TYPE_STRING, description='照片路径'),
            }
        )
    )
    def create(self, request, *args, **kwargs):
        request.data['order_number'] = id_factory.get_unique_id()
        request.data['user_id'] = request.user.id if request.user.id else 1
        request.data['status'] = CREDIT_STATUS_DICT.get('pending')
        request.data['score'] = calculate_credit_score(request.data['apply_type'])
        credit = CreditScoreDetail.objects.create(**request.data)
        response = CreditScoreDetailSerializer(credit).data
        return OK(data=response)

    def retrieve(self, request, id):
        credit_detail = CreditScoreDetail.objects.filter(id=id).first()
        return OK(data=CreditScoreDetailSerializer(credit_detail).data)

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='用户Id'),
                'to_user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='被转让人'),
                'credit_score': openapi.Schema(type=openapi.TYPE_INTEGER, description='申请分数')
            }
        )
    )
    @transaction.atomic()
    def transfer_credit(self, request, *args, **kwargs):
        user_query_set = ExtendedUser.objects.filter(user_id=request.data['user_id'])
        person_score = user_query_set.get().credit_score
        if person_score < request.data['credit_score']:
            raise BadRequest(ErrorCodeEnum.TRANSFER_CREDIT_SCORE_ERROR.value)
        # update two person credit score
        user_query_set.update(credit_score=person_score - request.data['credit_score'])

        to_user_query_set = ExtendedUser.objects.filter(user_id=request.data['to_user_id'])
        to_person_score = to_user_query_set.get().credit_score
        to_user_query_set.update(credit_score=to_person_score + request.data['credit_score'])

        request.data['apply_type'] = '000000001'
        request.data['status'] = CREDIT_STATUS_DICT.get('pass')
        credit = CreditScoreDetail.objects.create(**request.data)
        response = CreditScoreDetailSerializer(credit).data
        return OK(data=response)


class CreditScoreWorkflowViewSet(BaseModelViewSet):
    """
    deduct:
        管理员进行扣分操作
    approve:
        管理员进行审批操作
    """

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'apply_user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='申请人Id'),
                'apply_type': openapi.Schema(type=openapi.TYPE_STRING,
                                             description='申请类型,9为字符串， 01代表申请/扣分类型, 000000000: 分别代表:实验成果, '
                                                         '竞赛奖励, 协助加工, 助教助研, 爽约, 未打扫, 耗材用量过多, 超时, 信用分转让'),
                'reason': openapi.Schema(type=openapi.TYPE_STRING, description='申请理由'),
            }
        )
    )
    @transaction.atomic()
    def deduct(self, request, *args, **kwargs):
        request.data['user_id'] = request.data['apply_user_id']
        # 管理员的操作默认状态为pass
        request.data['status'] = CREDIT_STATUS_DICT.get('pass')
        request.data['credit_score'] = calculate_credit_score(request.data['apply_type'])
        request.data.pop('apply_user_id', None)
        credit = CreditScoreDetail.objects.create(**request.data)
        # 更新用户信用分， 若用户信用分不够当前扣除，则赋0分
        user_query_set = ExtendedUser.objects.filter(user_id=request.data['user_id'])
        person_score = user_query_set.get().credit_score
        if person_score < request.data['credit_score']:
            request.data['credit_score'] = person_score
        # 因为计算的值已经是负数 因此直接plus即可
        user_query_set.update(credit_score=person_score + request.data['credit_score'])
        response = CreditScoreDetailSerializer(credit).data
        return OK(data=response)

    @swagger_auto_schema(
        request_body=openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties={
                'credit_score_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='信用分申请Id'),
                'status': openapi.Schema(type=openapi.TYPE_INTEGER, description='通过(1) Or 拒绝(2)'),
                'reject_reason': openapi.Schema(type=openapi.TYPE_STRING, description='拒绝理由'),
            }
        )
    )
    @transaction.atomic()
    def approve(self, request, *args, **kwargs):
        credit_score_query_set = CreditScoreDetail.objects.filter(id=request.data['credit_score_id'])
        credit_detail = credit_score_query_set.get()
        credit_score_query_set.update(status=request.data.get('status'),
                                      reject_reason=request.data.get('reject_reason'))
        # 更新用户信用分
        if request.data['status'] == CREDIT_STATUS_DICT.get('pass'):
            user_query_set = ExtendedUser.objects.filter(user_id=credit_detail.user_id)
            user_query_set.update(credit_score=user_query_set.get().credit_score + credit_detail.credit_score)
        response = CreditScoreDetailSerializer(credit_detail).data
        return OK(data=response)


def calculate_credit_score(apply_type: str):
    credit_score = 0
    for i in range(len(apply_type)):
        if apply_type[i] == '1':
            credit_score += CREDIT_SCORE_LIST[i].value.get("score")

    return credit_score
